﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Reflection;
using Medianamik.Core.Logging;

namespace Medianamik.Core.Sugar
{
    [Serializable ()]
    public class TypeResolver : MarshalByRefObject
    {
        private static ILogger _logger;
        public static ILogger Logger
        {
            get
            {
                return _logger
                ?? (_logger = new ObjectFactory<ILogger>().Get("TypeResolverLogger"));
            }
        }

        public static string[] GetAssignablesFromType<T>(string path, string filePattern)
        {
            var files = Directory.GetFiles(path, filePattern).Select(s => new FileInfo(s).FullName);
            return GetAssignablesFromType<T>(files.ToArray());
        }

        public static string[] GetAssignablesFromType<T>(string[] files)
        {
            AppDomainSetup domainSetup = new AppDomainSetup();
            domainSetup.ApplicationBase = Path.GetDirectoryName(files.Single(f => f.Contains("Medianamik.Core")));
            domainSetup.ApplicationName = "Medianamik_Sandbox_" + Guid.NewGuid();
            domainSetup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
            domainSetup.DynamicBase = AppDomain.CurrentDomain.SetupInformation.DynamicBase;
            domainSetup.LicenseFile = AppDomain.CurrentDomain.SetupInformation.LicenseFile;
            domainSetup.LoaderOptimization = AppDomain.CurrentDomain.SetupInformation.LoaderOptimization;
            domainSetup.PrivateBinPath = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath;
            domainSetup.PrivateBinPathProbe = AppDomain.CurrentDomain.SetupInformation.PrivateBinPathProbe;
            domainSetup.ShadowCopyFiles = "false";
            
            AppDomain sandbox = AppDomain.CreateDomain("Sandbox",
                AppDomain.CurrentDomain.Evidence, domainSetup);
                       
            try
            {
                TypeResolver typeResolver = (TypeResolver)sandbox.CreateInstanceAndUnwrap(
                    typeof(TypeResolver).Assembly.GetName().Name,
                    typeof(TypeResolver).FullName);

                return typeResolver.GetTypes(typeof(T), files);
            }
            catch (Exception ex)
            {
                Logger.Error("Error Loading Assignable Types from " + typeof(T).Name, ex); 
            }
            finally
            {
                AppDomain.Unload(sandbox);
            }
            return new string[0];
        }

        public string[] GetTypes(Type assignTypeFrom, IEnumerable<string> assemblyFiles)
        {
            List<string> result = new List<string>();
            foreach (string fileName in assemblyFiles)
            {
                if (!File.Exists(fileName))
                    continue;
                try
                {
                    Assembly assembly = Assembly.LoadFile(fileName);
                    foreach (Type t in assembly.GetTypes())
                    {
                        if (!t.IsInterface && assignTypeFrom.IsAssignableFrom(t)
                            && !t.IsGenericTypeDefinition )
                            result.Add(t.AssemblyQualifiedName);
                    }
                }
                catch
                {
                    //Logger.Warn(string.Format("Error loading assembly: {0}", fileName), e);
                }
            }
            return result.ToArray();
        }
               
    }
}
